
#include "StreamPreviewWidget.h"

int StreamPreviewWidget::getCameraResolution(const int deviceIdx, int &width, int &height)
{
#if TESTMODE
	width = 640, height = 480;
	return 0;
#endif
	if (camera)
	{
		IplImage* img = cvQueryFrame(camera);
		width = img->width;
		height = img->height;
		return 0;
	}

	// start web-cam capture
	m_cameraLock.lock();
	camera = cvCreateCameraCapture(deviceIdx);
	IplImage* img = cvQueryFrame(camera);
	width = img->width;
	height = img->height;
	cvReleaseCapture(&camera);
	camera = 0;
	m_cameraLock.unlock();

	return 1;
}

int StreamPreviewWidget::stopCamera()
{
	m_cameraLock.lock();
	if (camera)
		cvReleaseCapture(&camera);
	camera = 0;
	m_cameraLock.unlock();

	return 0;
}

void StreamPreviewWidget::updateImageData()
{
	int strike = m_nVideoWidth * 3;
	for (int i=0; i<m_nVideoHeight; i++)
	{
		for (int j=0; j<m_nVideoWidth; j++)
		{
			QRgb rgb = m_imgVideo->pixel(j, i);
			*(m_lpRawImageData + i * strike + j * 3 + 2) = qRed(rgb);
			*(m_lpRawImageData + i * strike + j * 3 + 1) = qGreen(rgb);
			*(m_lpRawImageData + i * strike + j * 3 + 0) = qBlue(rgb);
		}
	}
}

void StreamPreviewWidget::updateImage()
{
	if (m_bPaused)
		return;

	m_cameraLock.lock();
	IplImage* cvimage = 0;
	if (camera)
		cvimage = cvQueryFrame(camera);
	m_cameraLock.unlock();

	if (!cvimage)
		return;

	// declare a dummy image
	QImage image(cvimage->width, cvimage->height, QImage::Format_RGB32);

	int cvIndex, cvLineStart;
	// switch between bit depths
	switch (cvimage->depth) {
		case IPL_DEPTH_8U:
			switch (cvimage->nChannels) {
				case 3:
					cvIndex = 0; cvLineStart = 0;
					for (int y = 0; y < cvimage->height; y++)
					{
						unsigned char red,green,blue;
						cvIndex = cvLineStart;
						for (int x = 0; x < cvimage->width; x++)
						{
							red = cvimage->imageData[cvIndex+2];
							green = cvimage->imageData[cvIndex+1];
							blue = cvimage->imageData[cvIndex+0];

							image.setPixel(x,y,qRgb(red, green, blue));
							cvIndex += 3;
						}
						cvLineStart += cvimage->widthStep;
					}
					break;
				default:
					break;
			}
			break;
		default:
			break;
	}

	if (m_nVideoWidth != image.width() || m_nVideoHeight != image.height())
		*m_imgVideo = image.scaled(m_nVideoWidth, m_nVideoHeight);
	else
		*m_imgVideo = image;

	updateImageData();
	if (!m_bPlayback)
		QMetaObject::invokeMethod(this, "updatePreviewImage", Qt::QueuedConnection);

	emit onCaptureVideo(m_nVideoWidth, m_nVideoHeight, (const unsigned char*)m_lpRawImageData);
}

void StreamPreviewWidget::updatePreviewImage()
{
	if (m_imgVideo->width() != 320 || m_imgVideo->height() != 240)
		m_imgVideo->scaled(320, 240);

	m_lblVideo->setPixmap(QPixmap::fromImage(*m_imgVideo));
}

StreamPreviewWidget::StreamPreviewWidget(const int deviceIdx, const int fps, const int vWidth, const int vHeight) :
	camera(0), m_bExit(0), m_cameraLock(), m_nFps(fps), m_bPaused(false), m_bPlayback(false),
	m_nVideoWidth(vWidth), m_nVideoHeight(vHeight)
{
	if (m_nVideoHeight == 0 || m_nVideoWidth == 0)
		getCameraResolution(deviceIdx, m_nVideoWidth, m_nVideoHeight);

	// start web-cam capture
	m_cameraLock.lock();
	camera = cvCreateCameraCapture(deviceIdx);
	m_cameraLock.unlock();

	// create interface
	createInterface();

	// create fixed image data
	m_lpRawImageData = (unsigned char*)malloc(MAX_VIDEO_WIDTH * MAX_VIDEO_HEIGHT * 3);

	// create decoder
	m_lpDecoder = new VideoDecoder();
	connect(m_lpDecoder, SIGNAL(onDecoded(const int, const int)), this, SLOT(onDecoded(const int, const int)));
	m_lpDecoder->start();

	// start current thread
	m_lpUpdater = new VideoUpdater(this);
	m_lpUpdater->start();
}

StreamPreviewWidget::~StreamPreviewWidget(void)
{
	// stop camera if it was started
	stopCamera();

	m_bExit = 1;
	m_lpUpdater->waitToExit();
	delete m_lpUpdater;

	delete m_lpDecoder;

	// free fixed image data
	free(m_lpRawImageData);
}

void StreamPreviewWidget::createInterface()
{
	m_lblVideo = new QLabel();
	m_lblVideo->setFixedSize(320, 240);
	m_imgVideo = new QImage(m_nVideoWidth, m_nVideoHeight, QImage::Format_RGB32);
	m_lblVideo->setFrameStyle(1);
	m_lblVideo->setPixmap(QPixmap::fromImage(*m_imgVideo));

	QVBoxLayout *layout = new QVBoxLayout();
	layout->addWidget(m_lblVideo, 0, Qt::AlignCenter);
	setLayout(layout);

	setTitle(tr(TITLE_SECTION_PREVIEW));
}

void StreamPreviewWidget::reset(const int deviceIdx, const int fps, const int vWidth, const int vHeight)
{
	stopCamera();

	m_nVideoWidth = vWidth;
	m_nVideoHeight = vHeight;
	if (m_nVideoHeight == 0 || m_nVideoWidth == 0)
		getCameraResolution(deviceIdx, m_nVideoWidth, m_nVideoHeight);

	m_cameraLock.lock();
	m_nFps = fps;
	// start web-cam capture
	camera = cvCreateCameraCapture(deviceIdx);
	m_cameraLock.unlock();
}

void StreamPreviewWidget::decodePackets(PacketList *packets)
{
	m_lpDecoder->decode(packets);
}

void StreamPreviewWidget::onDecoded(const int width, const int height)
{
	const unsigned char *rawData = m_lpDecoder->rawData();

	int curLine = 0;
	for (int y=0; y<height; y++)
	{
		unsigned char red,green,blue;
		int curCol = curLine;
		for (int x=0; x<width; x++)
		{
			red = rawData[curCol+2];
			green = rawData[curCol+1];
			blue = rawData[curCol+0];

			m_imgVideo->setPixel(x, y, qRgb(red, green, blue));
			curCol += 3;
		}
		curLine += width * 3;
	}
	QMetaObject::invokeMethod(this, "updatePreviewImage", Qt::QueuedConnection);
}
